bitkeeper revision 1.831 (406995dbwlqGk2qHrfw3kwGxQ37WSw)
authoriap10@tetris.cl.cam.ac.uk <iap10@tetris.cl.cam.ac.uk>
Tue, 30 Mar 2004 15:44:27 +0000 (15:44 +0000)
committeriap10@tetris.cl.cam.ac.uk <iap10@tetris.cl.cam.ac.uk>
Tue, 30 Mar 2004 15:44:27 +0000 (15:44 +0000)
Flush and clean shadow page table ops added.
Add 'dist' target back to Xen Makefile.

tools/xc/py/Xc.c
xen/Makefile
xen/common/shadow.c
xen/include/asm-i386/processor.h
xen/include/hypervisor-ifs/dom0_ops.h
xen/include/xen/shadow.h

index 96b9bf491ab151b0b90e9921bf90934a64da3dca..4c82b03d73f5bd62629df6b0af3a98da235eb9c9 100644 (file)
@@ -914,6 +914,28 @@ static PyObject *pyxc_rrobin_global_set(PyObject *self,
     return zero;
 }
 
+static PyObject *pyxc_shadow_control(PyObject *self,
+                                     PyObject *args,
+                                     PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+
+    u64 dom;
+    int op=0;
+
+    static char *kwd_list[] = { "dom", "op", NULL };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "L|i", kwd_list, 
+                                      &dom, &op) )
+        return NULL;
+
+    if ( xc_shadow_control(xc->xc_handle, dom, op) != 0 )
+        return PyErr_SetFromErrno(xc_error);
+    
+    Py_INCREF(zero);
+    return zero;
+}
+
 
 static PyMethodDef pyxc_methods[] = {
     { "domain_create", 
@@ -1211,6 +1233,15 @@ static PyMethodDef pyxc_methods[] = {
       "Returns [dict]: information about the hardware"
       "        [None]: on failure.\n" },
 
+    { "shadow_control", 
+      (PyCFunction)pyxc_shadow_control, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Set parameter for shadow pagetable interface\n"
+      " dom [long]:    Identifier of domain.\n"
+      " op [int, 0]: operation\n\n"
+      "Returns: [int] 0 on success; -1 on error.\n" },
+
+
     { NULL, NULL, 0, NULL }
 };
 
index e887dd2235af9ec3b20827c4f27e3dc1068aa6fb..cfe5e1242cb025aa29ce06309d4a1400a37a04ed 100644 (file)
@@ -22,6 +22,9 @@ install: $(TARGET)
        mkdir -p $(prefix)/boot
        install -m0644 $(TARGET).gz $(prefix)/boot
 
+dist: $(TARGET)
+       $(MAKE) prefix=`pwd`/../../install dist=yes install
+
 clean: delete-links
        $(MAKE) -C tools clean
        $(MAKE) -C common clean
index dc6705ab195c21fb3fe6ef3c3e90789fdd74aa4c..600f8211f43b683cc19fcf834bd8633e1bc580b5 100644 (file)
@@ -26,54 +26,138 @@ hypercall lock anyhow (at least initially).
 
 ********/
 
-static inline void free_shadow_page( struct mm_struct *m, unsigned int pfn )
+static inline void free_shadow_page( struct mm_struct *m, 
+                                                                        struct pfn_info *pfn_info )
 {
     unsigned long flags;
+       unsigned long type = pfn_info->type_and_flags & PGT_type_mask;
 
        m->shadow_page_count--;
 
+       if (type == PGT_l1_page_table)
+               perfc_decr(shadow_l1_pages);
+    else if (type == PGT_l2_page_table)
+               perfc_decr(shadow_l2_pages);
+       else printk("Free shadow weird page type pfn=%08x type=%08lx\n",
+                               frame_table-pfn_info, pfn_info->type_and_flags);
+                               
+
+       pfn_info->type_and_flags = 0;
+
     spin_lock_irqsave(&free_list_lock, flags);
-    list_add(&frame_table[pfn].list, &free_list);
+    list_add(&pfn_info->list, &free_list);
     free_pfns++;
     spin_unlock_irqrestore(&free_list_lock, flags);
 }
 
 static void __free_shadow_table( struct mm_struct *m )
 {
-       int j;
-       struct shadow_status *a;
+       int j, free=0;
+       struct shadow_status *a,*next;
        
        // the code assumes you're not using the page tables i.e.
     // the domain is stopped and cr3 is something else!!
 
     // walk the hash table and call free_shadow_page on all pages
 
+       shadow_audit(m,1);
+
     for(j=0;j<shadow_ht_buckets;j++)
     {
         a = &m->shadow_ht[j];        
         if (a->pfn)
         {
-            free_shadow_page( m, a->spfn_and_flags & PSH_pfn_mask );
+            free_shadow_page( m, 
+                          &frame_table[a->spfn_and_flags & PSH_pfn_mask] );
             a->pfn = 0;
             a->spfn_and_flags = 0;
+            free++;
         }
-        a=a->next;
+        next=a->next;
+        a->next=NULL;
+        a=next;
         while(a)
                { 
             struct shadow_status *next = a->next;
-            free_shadow_page( m, a->spfn_and_flags & PSH_pfn_mask );
+
+            free_shadow_page( m, 
+                          &frame_table[a->spfn_and_flags & PSH_pfn_mask] );
             a->pfn = 0;
             a->spfn_and_flags = 0;
-            a->next = m->shadow_ht_free;
+            free++;
+            a->next = m->shadow_ht_free;           
             m->shadow_ht_free = a;
             a=next;
                }
+       shadow_audit(m,0);
        }
+   SH_LOG("Free shadow table. Freed= %d",free);
 }
 
+static inline int shadow_page_op( struct mm_struct *m, unsigned int op,
+                                   struct pfn_info *spfn_info )
+{
+    int work = 0;
+    unsigned int spfn = spfn_info-frame_table;
 
-int shadow_mode_enable( struct mm_struct *m, unsigned int mode )
+    switch( op )
+    {
+        case DOM0_SHADOW_CONTROL_OP_CLEAN:
+        {
+            int i;
+            if ( (spfn_info->type_and_flags & PGT_type_mask) == 
+                                                      PGT_l1_page_table )
+            {
+                unsigned long * spl1e = map_domain_mem( spfn<<PAGE_SHIFT );
+
+                for (i=0;i<ENTRIES_PER_L1_PAGETABLE;i++)
+                {                    
+                    if ( spl1e[i] & _PAGE_RW )
+                    {
+                        work++;
+                        spl1e[i] &= ~_PAGE_RW;
+                    }
+                }
+                unmap_domain_mem( spl1e );
+            }
+        }
+    }
+    return work;
+}
+static void __scan_shadow_table( struct mm_struct *m, unsigned int op )
 {
+       int j, work=0;
+       struct shadow_status *a;
+       
+       // the code assumes you're not using the page tables i.e.
+    // the domain is stopped and cr3 is something else!!
+
+    // walk the hash table and call free_shadow_page on all pages
+
+       shadow_audit(m,1);
+
+    for(j=0;j<shadow_ht_buckets;j++)
+    {
+        a = &m->shadow_ht[j];        
+        if (a->pfn)
+        {
+            work += shadow_page_op( m, op, &frame_table[a->spfn_and_flags & PSH_pfn_mask] );
+        }
+        a=a->next;
+        while(a)
+               { 
+            work += shadow_page_op( m, op, &frame_table[a->spfn_and_flags & PSH_pfn_mask] );
+            a=a->next;
+               }
+       shadow_audit(m,0);
+       }
+   SH_LOG("Scan shadow table. Work=%d l1=%d l2=%d", work, perfc_value(shadow_l1_pages), perfc_value(shadow_l2_pages));
+}
+
+
+int shadow_mode_enable( struct task_struct *p, unsigned int mode )
+{
+    struct mm_struct *m = &p->mm;
        struct shadow_status **fptr;
        int i;
 
@@ -102,6 +186,8 @@ int shadow_mode_enable( struct mm_struct *m, unsigned int mode )
 
        memset( m->shadow_ht_extras, 0, sizeof(void*) + (shadow_ht_extra_size * 
                                                           sizeof(struct shadow_status)) );
+
+    m->shadow_extras_count++;
        
     // add extras to free list
        fptr = &m->shadow_ht_free;
@@ -114,6 +200,13 @@ int shadow_mode_enable( struct mm_struct *m, unsigned int mode )
        *((struct shadow_status ** ) 
         &m->shadow_ht_extras[shadow_ht_extra_size]) = NULL;
 
+    if ( mode == SHM_logdirty )
+    {
+        m->shadow_dirty_bitmap = kmalloc( p->max_pages/8, GFP_KERNEL );
+        if( !m->shadow_dirty_bitmap  ) goto nomem;
+        memset(m->shadow_dirty_bitmap,0,p->max_pages/8);
+    }
+
        spin_unlock(&m->shadow_lock);
 
     // call shadow_mk_pagetable
@@ -126,16 +219,43 @@ nomem:
        return -ENOMEM;
 }
 
-static void shadow_mode_disable( struct mm_struct *m )
+static void shadow_mode_disable( struct task_struct *p )
 {
+    struct mm_struct *m = &p->mm;
+       struct shadow_status *next;
+
+    spin_lock(&m->shadow_lock);
+       __free_shadow_table( m );
+       m->shadow_mode = 0;
+       spin_unlock(&m->shadow_lock);
+
+       SH_LOG("freed tables count=%d l1=%d l2=%d",
+                  m->shadow_page_count, perfc_value(shadow_l1_pages), perfc_value(shadow_l2_pages));
+
+       next = m->shadow_ht_extras;
+       while( next )
+    {
+               struct shadow_status * this = next;
+               m->shadow_extras_count--;
+               next = *((struct shadow_status **)(&next[shadow_ht_extra_size]));
+               kfree( this );
+       }
 
-    // free the hash buckets as you go
+       SH_LOG("freed extras, now %d", m->shadow_extras_count);
+
+    if( m->shadow_dirty_bitmap  )
+    {
+        kfree( m->shadow_dirty_bitmap );
+               m->shadow_dirty_bitmap = 0;
+    }
 
     // free the hashtable itself
+       kfree( &m->shadow_ht[0] );
 }
 
-static void shadow_mode_flush( struct mm_struct *m )
+static void shadow_mode_table_op( struct task_struct *p, unsigned int op )
 {
+       struct mm_struct *m = &p->mm;
 
     // since Dom0 did the hypercall, we should be running with it's page
     // tables right now. Calling flush on yourself would be really
@@ -147,10 +267,32 @@ static void shadow_mode_flush( struct mm_struct *m )
         return;
     }
    
+
     spin_lock(&m->shadow_lock);
-       __free_shadow_table( m );
+
+    SH_LOG("shadow mode table op %08lx %08lx count %d",pagetable_val( m->pagetable),pagetable_val(m->shadow_table), m->shadow_page_count);
+
+    shadow_audit(m,1);
+
+    switch(op)
+    {
+    case DOM0_SHADOW_CONTROL_OP_FLUSH:
+           __free_shadow_table( m );
+        break;
+   
+    case DOM0_SHADOW_CONTROL_OP_CLEAN:
+       __scan_shadow_table( m, op );
+       if( m->shadow_dirty_bitmap )
+           memset(m->shadow_dirty_bitmap,0,p->max_pages/8);
+       break;
+    }
+
        spin_unlock(&m->shadow_lock);
 
+    SH_LOG("shadow mode table op : page count %d", m->shadow_page_count);
+
+    shadow_audit(m,1);
+
     // call shadow_mk_pagetable
     shadow_mk_pagetable( m );
 
@@ -164,28 +306,30 @@ int shadow_mode_control( struct task_struct *p, unsigned int op )
     // don't call if already shadowed...
 
        // sychronously stop domain
-    if( !(p->state & TASK_STOPPED) && !(p->state & TASK_PAUSED))
+    if( 0 && !(p->state & TASK_STOPPED) && !(p->state & TASK_PAUSED))
     {
+        printk("about to pause domain\n");
            sched_pause_sync(p);
         printk("paused domain\n");
         we_paused = 1;
     }
 
-       if (p->mm.shadow_mode && op == DOM0_SHADOW_CONTROL_OP_OFF )
+       if ( p->mm.shadow_mode && op == DOM0_SHADOW_CONTROL_OP_OFF )
     {
-               shadow_mode_disable(&p->mm);
+               shadow_mode_disable(p);
        }
-       else if (p->mm.shadow_mode && op == DOM0_SHADOW_CONTROL_OP_ENABLE_TEST )
+       else if ( op == DOM0_SHADOW_CONTROL_OP_ENABLE_TEST )
        {
-        shadow_mode_disable(&p->mm);
-        shadow_mode_enable(&p->mm, SHM_test);
+        if(p->mm.shadow_mode) shadow_mode_disable(p);
+        shadow_mode_enable(p, SHM_test);
        }       
-       else if (p->mm.shadow_mode && op == DOM0_SHADOW_CONTROL_OP_FLUSH )
+       else if ( p->mm.shadow_mode && op >= DOM0_SHADOW_CONTROL_OP_FLUSH && op<=DOM0_SHADOW_CONTROL_OP_CLEAN )
     {
-               shadow_mode_flush(&p->mm);
+               shadow_mode_table_op(p, op);
     }
        else
     {
+        if ( we_paused ) wake_up(p);
                return -EINVAL;
     }
 
@@ -220,6 +364,7 @@ void unshadow_table( unsigned long gpfn, unsigned int type )
     // this CPU was the one that cmpxchg'ed the page to invalid
 
        spfn = __shadow_status(&current->mm, gpfn) & PSH_pfn_mask;
+
        delete_shadow_status(&current->mm, gpfn);
 
 #if 0 // XXX leave as might be useful for later debugging
@@ -235,12 +380,7 @@ void unshadow_table( unsigned long gpfn, unsigned int type )
        }
 #endif
 
-       if (type == PGT_l1_page_table)
-               perfc_decr(shadow_l1_pages);
-    else
-               perfc_decr(shadow_l2_pages);
-
-       free_shadow_page( &current->mm, spfn );
+       free_shadow_page( &current->mm, &frame_table[spfn] );
 
 }
 
@@ -256,7 +396,6 @@ unsigned long shadow_l2_table(
        SH_VVLOG("shadow_l2_table( %08lx )",gpfn);
 
        perfc_incrc(shadow_l2_table_count);
-       perfc_incr(shadow_l2_pages);
 
     // XXX in future, worry about racing in SMP guests 
     //      -- use cmpxchg with PSH_pending flag to show progress (and spin)
@@ -265,6 +404,9 @@ unsigned long shadow_l2_table(
 
     ASSERT( spfn_info ); // XXX deal with failure later e.g. blow cache
 
+       spfn_info->type_and_flags = PGT_l2_page_table;
+       perfc_incr(shadow_l2_pages);
+
        spfn = (unsigned long) (spfn_info - frame_table);
 
        // mark pfn as being shadowed, update field to point at shadow
@@ -434,7 +576,9 @@ int shadow_fault( unsigned long va, long error_code )
             struct pfn_info *sl1pfn_info;
             unsigned long *gpl1e, *spl1e;
             int i;
-            sl1pfn_info = alloc_domain_page( NULL ); // XXX account properly! 
+            sl1pfn_info = alloc_shadow_page( &current->mm ); 
+               sl1pfn_info->type_and_flags = PGT_l1_page_table;
+
             sl1pfn = sl1pfn_info - frame_table;
 
             SH_VVLOG("4a: l1 not shadowed ( %08lx )",sl1pfn);
index 60c70d90373631bfe566c75dea8ab5892e863bb6..b7aa895bfdb5d6e3e03fdb8013e4f0217dbbb26f 100644 (file)
@@ -426,8 +426,10 @@ struct mm_struct {
     struct shadow_status *shadow_ht;
     struct shadow_status *shadow_ht_free;
     struct shadow_status *shadow_ht_extras; // extra allocation units
+    unsigned int *shadow_dirty_bitmap;
     unsigned int shadow_page_count;
     unsigned int shadow_max_page_count;
+    unsigned int shadow_extras_count;
 
     /* Current LDT details. */
     unsigned long ldt_base, ldt_ents, shadow_ldt_mapcnt;
index f3f93a289e64c1b9397a4d49073be8f2a16c2d41..70cf92225ba5d5891e1780178810007da1edef24 100644 (file)
@@ -221,7 +221,9 @@ typedef struct dom0_pcidev_access_st
 
 #define DOM0_SHADOW_CONTROL_OP_OFF         0
 #define DOM0_SHADOW_CONTROL_OP_ENABLE_TEST 1
+#define DOM0_SHADOW_CONTROL_OP_ENABLE_LOGDIRTY 2
 #define DOM0_SHADOW_CONTROL_OP_FLUSH       10
+#define DOM0_SHADOW_CONTROL_OP_CLEAN       11
 typedef struct dom0_shadow_control_st
 {
     /* IN variables. */
index a9d03b4198e6a3ec7e74299ee2293ae58a5f87c3..0f4e2e19d46bb35f3e07ee3a0fcbe6b44d22a22d 100644 (file)
 #define PSH_pfn_mask   ((1<<21)-1)
 
 /* Shadow PT operation mode : shadowmode variable in mm_struct */
-#define SHM_test        (1<<0) /* just run domain on shadow PTs */
-#define SHM_logdirty    (1<<1) /* log pages that are dirtied */
-#define SHM_cow         (1<<2) /* copy on write all dirtied pages */
-#define SHM_translate   (1<<3) /* lookup machine pages in translation table */
+#define SHM_test        (1) /* just run domain on shadow PTs */
+#define SHM_logdirty    (2) /* log pages that are dirtied */
+#define SHM_cow         (3) /* copy on write all dirtied pages */
+#define SHM_translate   (4) /* lookup machine pages in translation table */
 
 #define shadow_linear_pg_table ((l1_pgentry_t *)SH_LINEAR_PT_VIRT_START)
 #define shadow_linear_l2_table ((l2_pgentry_t *)(SH_LINEAR_PT_VIRT_START+(SH_LINEAR_PT_VIRT_START>>(L2_PAGETABLE_SHIFT-L1_PAGETABLE_SHIFT))))
@@ -30,7 +30,7 @@ extern void shadow_l1_normal_pt_update( unsigned long pa, unsigned long gpte,
                                                                                l1_pgentry_t **prev_spl1e_ptr  );
 extern void shadow_l2_normal_pt_update( unsigned long pa, unsigned long gpte );
 extern void unshadow_table( unsigned long gpfn, unsigned int type );
-extern int shadow_mode_enable( struct mm_struct *m, unsigned int mode );
+extern int shadow_mode_enable( struct task_struct *p, unsigned int mode );
 extern unsigned long shadow_l2_table( 
                      struct mm_struct *m, unsigned long gpfn );
 
@@ -81,26 +81,33 @@ static void shadow_audit(struct mm_struct *m, int print)
        
     for(j=0;j<shadow_ht_buckets;j++)
     {
-        a = &p->mm.shadow_ht[j];        
-               if(a->pfn) live++;
-        while(a->next && live<9999)
+        a = &m->shadow_ht[j];        
+               if(a->pfn){live++; ASSERT(a->spfn_and_flags&PSH_pfn_mask);}
+               ASSERT((a->pfn&0xf0000000)==0);
+               ASSERT(a->pfn<0x00100000);
+               a=a->next;
+        while(a && live<9999)
                { 
                        live++; 
-                       if(a->pfn == 0)
+                       if(a->pfn == 0 || a->spfn_and_flags == 0)
                        {
                                printk("XXX live=%d pfn=%08lx sp=%08lx next=%p\n",
                                           live, a->pfn, a->spfn_and_flags, a->next);
                                BUG();
                        }
+                       ASSERT(a->pfn);
+                       ASSERT((a->pfn&0xf0000000)==0);
+                       ASSERT(a->pfn<0x00100000);
+                       ASSERT(a->spfn_and_flags&PSH_pfn_mask);
                        a=a->next; 
                }
                ASSERT(live<9999);
        }
 
-    a = p->mm.shadow_ht_free;
+    a = m->shadow_ht_free;
     while(a) { free++; a=a->next; }
 
-    if(print) printk("live=%d free=%d\n",live,free);
+    if(print) printk("Xlive=%d free=%d\n",live,free);
 
        abs=(perfc_value(shadow_l1_pages)+perfc_value(shadow_l2_pages))-live;
        if( abs < -1 || abs > 1 )
@@ -214,6 +221,8 @@ static inline void delete_shadow_status( struct mm_struct *m,
 
                        b->next = b->next->next;
                        D->next = m->shadow_ht_free;
+                       D->pfn = 0;
+                       D->spfn_and_flags = 0;
                        m->shadow_ht_free = D;
                }
                else
@@ -224,6 +233,7 @@ static inline void delete_shadow_status( struct mm_struct *m,
 
 #if SHADOW_HASH_DEBUG
                if( __shadow_status(m,gpfn) ) BUG();  
+               shadow_audit(m,0);
 #endif
                return;
     }
@@ -246,6 +256,7 @@ static inline void delete_shadow_status( struct mm_struct *m,
 #if SHADOW_HASH_DEBUG
                        if( __shadow_status(m,gpfn) ) BUG();
 #endif
+                       shadow_audit(m,0);
                        return;
                }
 
@@ -268,8 +279,10 @@ static inline void set_shadow_status( struct mm_struct *m,
        B = b = hash_bucket( m, gpfn );
    
     ASSERT(gpfn);
-    ASSERT(s);
+    //ASSERT(s);
+    //ASSERT(s&PSH_pfn_mask);
     SH_VVLOG("set gpfn=%08x s=%08lx bucket=%p(%p)", gpfn, s, b, b->next );
+
     shadow_audit(m,0);
 
        do
@@ -277,6 +290,7 @@ static inline void set_shadow_status( struct mm_struct *m,
                if ( b->pfn == gpfn )                   
                {
                        b->spfn_and_flags = s;
+                       shadow_audit(m,0);
                        return;
                }
 
@@ -294,6 +308,7 @@ static inline void set_shadow_status( struct mm_struct *m,
         ASSERT( B->next == 0 );
                B->pfn = gpfn;
                B->spfn_and_flags = s;
+               shadow_audit(m,0);
                return;
        }
 
@@ -309,6 +324,8 @@ static inline void set_shadow_status( struct mm_struct *m,
 
            memset( extra, 0, sizeof(void*) + (shadow_ht_extra_size * 
                                                           sizeof(struct shadow_status)) );
+
+        m->shadow_extras_count++;
        
         // add extras to free list
            fptr = &m->shadow_ht_free;
@@ -319,7 +336,7 @@ static inline void set_shadow_status( struct mm_struct *m,
            }
            *fptr = NULL;
 
-           *((struct shadow_status ** ) &m->shadow_ht[shadow_ht_extra_size]) = 
+           *((struct shadow_status ** ) &extra[shadow_ht_extra_size]) = 
                                             m->shadow_ht_extras;
         m->shadow_ht_extras = extra;
 
@@ -333,6 +350,8 @@ static inline void set_shadow_status( struct mm_struct *m,
        b->next = B->next;
        B->next = b;
 
+       shadow_audit(m,0);
+
        return;
 }